import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useNetwork } from 'ahooks';
import { Upload, message, Progress, Card, Button, Tag } from 'antd';
import { UploadOutlined, CloseOutlined } from '@ant-design/icons';
import { eachLimit } from 'async';
import SparkMD5 from 'spark-md5';
import type { UploadChangeParam } from 'antd/lib/upload';
import styles from './LargeFileUpload.module.css';
import { http, host, port } from '../utils/host'
declare global {
    interface Navigator {
        connection?: {
            rtt?: number;
            effectiveType?: string;
            downlink?: number;
            saveData?: boolean;
        };
    }
}

interface ChunkInfo {
    chunk: Blob;
    hash: string;
    index: number;
    percentage: number;
    size: number;
}

interface UploadState {
    fileHash: string;
    fileName: string;
    fileType: string;
    chunks: ChunkInfo[];
    totalProgress: number;
    isUploading: boolean;
    isPaused: boolean;
}

// 文件类型分类
const FILE_TYPES: Record<string, string[]> = {
    IMAGE: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
    VIDEO: ['video/mp4', 'video/webm', 'video/ogg'],
    DOCUMENT: ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
    AUDIO: ['audio/mpeg', 'audio/wav', 'audio/ogg'],
    OTHER: []
};

const getFileType = (mimeType: string): string => {
    for (const [type, mimeTypes] of Object.entries(FILE_TYPES)) {
        if (mimeTypes.includes(mimeType)) {
            return type;
        }
    }
    return 'OTHER';
};

const getFileTypeColor = (type: string): string => {
    const colors: { [key: string]: string } = {
        IMAGE: 'blue',
        VIDEO: 'purple',
        DOCUMENT: 'green',
        AUDIO: 'orange',
        OTHER: 'default'
    };
    return colors[type] || 'default';
};

const API_BASE_URL = `${http}${host}${port}`; // 根据你的后端地址修改

const LargeFileUpload: React.FC = () => {
    const network = useNetwork();
    const [chunkSize, setChunkSize] = useState<number>(5 * 1024 * 1024); // 默认5MB
    const [concurrentLimit, setConcurrentLimit] = useState<number>(3);
    const [uploadStates, setUploadStates] = useState<UploadState[]>([]);
    const [retryCount, setRetryCount] = useState<{ [key: string]: number }>({});
    const workerRef = useRef<Worker | null>(null);
    const abortControllers = useRef<{ [fileHash: string]: AbortController }>({});
    const handledFileHashes = useRef<Set<string>>(new Set());
    const pausedUploads = useRef<Set<string>>(new Set());
    const isUploadingRef = useRef<{ [fileHash: string]: boolean }>({});

    // 网络状态监控和动态调整
    useEffect(() => {
        const { rtt = 0, effectiveType = '4g' } = navigator.connection || {};
        if (rtt < 100 && ['4g', '5g'].includes(effectiveType)) {
            setChunkSize(50 * 1024 * 1024); // 50MB
            setConcurrentLimit(5);
        } else if (rtt >= 100 && rtt < 500) {
            setChunkSize(10 * 1024 * 1024); // 10MB
            setConcurrentLimit(3);
        } else {
            setChunkSize(1 * 1024 * 1024); // 1MB
            setConcurrentLimit(1);
        }
    }, [network]);

    // 初始化 Web Worker
    useEffect(() => {
        const worker = new Worker('/upload.worker.js');
        workerRef.current = worker;
        worker.onmessage = (e) => {
            const { type, data } = e.data;
            switch (type) {
                case 'CHUNK_HASH_COMPLETE':
                    setUploadStates(prev => prev.map(state =>
                        state.fileHash === data.fileHash
                            ? { ...state, chunks: data.chunks, isUploading: true }
                            : state
                    ));
                    isUploadingRef.current[data.fileHash] = true;
                    setTimeout(() => {
                        handleUploadChunks(data.chunks, data.fileHash, data.fileName, data.fileType);
                    }, 0);
                    break;
                case 'HASH_PROGRESS':
                    // 可选：可为每个文件单独显示 hash 进度
                    break;
                case 'ERROR':
                    message.error(data.error);
                    break;
            }
        };
        return () => {
            worker.terminate();
        };
    }, []);

    // 计算文件hash
    const calculateHash = useCallback(async (file: File): Promise<string> => {
        return new Promise((resolve, reject) => {
            const spark = new SparkMD5.ArrayBuffer();
            const reader = new FileReader();
            const chunkSize = 2 * 1024 * 1024; // 2MB chunks for hash calculation
            let currentChunk = 0;
            const chunks = Math.ceil(file.size / chunkSize);
            reader.onload = (e) => {
                spark.append(e.target?.result as ArrayBuffer);
                currentChunk++;
                if (currentChunk < chunks) {
                    loadNext();
                } else {
                    resolve(spark.end());
                }
            };
            reader.onerror = () => {
                reject(new Error('Failed to read file for hash calculation'));
            };
            function loadNext() {
                const start = currentChunk * chunkSize;
                const end = Math.min(start + chunkSize, file.size);
                reader.readAsArrayBuffer(file.slice(start, end));
            }
            loadNext();
        });
    }, []);

    // 文件分片
    const createFileChunks = useCallback((file: File): Blob[] => {
        const chunks: Blob[] = [];
        let cur = 0;
        while (cur < file.size) {
            chunks.push(file.slice(cur, cur + chunkSize));
            cur += chunkSize;
        }
        return chunks;
    }, [chunkSize]);

    // 验证文件分片是否已上传
    const verifyChunks = async (fileHash: string): Promise<string[]> => {
        try {
            const response = await fetch(`${API_BASE_URL}/upload/verify`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ fileHash })
            });
            if (!response.ok) {
                throw new Error('验证失败');
            }
            const data = await response.json();
            return data.data.uploadedChunks;
        } catch (error) {
            console.error('验证分片失败:', error);
            return [];
        }
    };

    // 处理文件上传
    const handleUploadChunks = useCallback(
        async (chunks: ChunkInfo[], fileHash: string, fileName: string, fileType: string) => {
            if (pausedUploads.current.has(fileHash)) {
                return;
            }
            // 独立的 abort controller
            if (abortControllers.current[fileHash]) {
                abortControllers.current[fileHash].abort();
            }
            abortControllers.current[fileHash] = new AbortController();
            const uploadedChunks = await verifyChunks(fileHash);
            const remainingChunks = chunks.filter(chunk => !uploadedChunks.includes(chunk.index.toString()));
            // 单个分片上传并重试
            const uploadSingleChunk = async (chunk: ChunkInfo, fileHash: string, fileName: string, callback: (err?: Error) => void) => {
                if (!isUploadingRef.current[fileHash]) {
                    return;
                }
                try {
                    const formData = new FormData();
                    formData.append('fileHash', fileHash);
                    formData.append('index', chunk.index.toString());
                    formData.append('chunk', chunk.chunk);
                    formData.append('hash', chunk.hash);
                    const response = await fetch(`${API_BASE_URL}/upload/chunk`, {
                        method: 'POST',
                        body: formData,
                        signal: abortControllers.current[fileHash]?.signal
                    });
                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status}`);
                    }
                    // 更新分片进度和总进度
                    setUploadStates(prev => prev.map(state => {
                        if (state.fileHash !== fileHash) return state;
                        const newChunks = state.chunks.map(c =>
                            c.index === chunk.index ? { ...c, percentage: 100 } : c
                        );
                        const totalProgress = newChunks.reduce((acc, c) => acc + c.percentage, 0) / newChunks.length;
                        return { ...state, chunks: newChunks, totalProgress };
                    }));
                    callback();
                } catch (error) {
                    if (!isUploadingRef.current[fileHash]) {
                        return;
                    }
                    const currentRetryCount = (retryCount[chunk.hash] || 0) + 1;
                    if (currentRetryCount <= 3) {
                        setRetryCount(prev => ({
                            ...prev,
                            [chunk.hash]: currentRetryCount
                        }));
                        setTimeout(() => {
                            uploadSingleChunk(chunk, fileHash, fileName, callback);
                        }, 1000 * currentRetryCount);
                    } else {
                        message.error(`分片 ${chunk.index} 上传失败，已重试3次`);
                        callback(error instanceof Error ? error : new Error(String(error)));
                    }
                }
            };
            try {
                await new Promise((resolve, reject) => {
                    eachLimit(remainingChunks, concurrentLimit, (chunk: ChunkInfo, callback) => {
                        uploadSingleChunk(chunk, fileHash, fileName, callback);
                    }, async (err) => {
                        if (err) {
                            reject(err);
                            return;
                        }
                        // 所有分片上传完后再合并
                        try {
                            const response = await fetch(`${API_BASE_URL}/upload/merge`, {
                                method: 'POST',
                                headers: {
                                    'Content-Type': 'application/json'
                                },
                                body: JSON.stringify({ fileHash, fileName, fileType })
                            });
                            if (!response.ok) {
                                throw new Error('合并请求失败');
                            }
                            const result = await response.json();



const fileUrls = JSON.parse(localStorage.getItem('fileUrls') || '[]');
fileUrls.push(result.data.path);
localStorage.setItem('fileUrls', JSON.stringify(fileUrls));





                            message.success(`${fileName} 上传成功`);
                            setUploadStates(prev => prev.map(state =>
                                state.fileHash === fileHash
                                    ? { ...state, isUploading: false, totalProgress: 100 }
                                    : state
                            ));
                            isUploadingRef.current[fileHash] = false;
                            // 新增：合并成功后彻底清理abortController，防止重试
                            delete abortControllers.current[fileHash];
                            resolve(result);
                        } catch (error) {
                            message.error('文件合并失败');
                            reject(error);
                        }
                    });
                });
            } catch (error) {
                message.error('上传失败');
                console.error('上传错误:', error);
            } finally {
                // 新增：合并成功或失败后都清理abortController
                delete abortControllers.current[fileHash];
            }
        },
        [concurrentLimit, retryCount]
    );

    // 处理文件选择
    const handleFileChange = useCallback(async (info: UploadChangeParam) => {
        const files = info.fileList.map(f => f.originFileObj).filter(Boolean) as File[];
        for (const file of files) {
            const fileHash = await calculateHash(file);
            if (handledFileHashes.current.has(fileHash)) continue;
            handledFileHashes.current.add(fileHash);
            const fileType = getFileType(file.type);

            setUploadStates(prev => [
                ...prev,
                {
                    fileHash,
                    fileName: file.name,
                    fileType,
                    chunks: [],
                    totalProgress: 0,
                    isUploading: false,
                    isPaused: false
                }
            ]);
            const chunks = createFileChunks(file);
            workerRef.current?.postMessage({
                type: 'PROCESS_CHUNKS',
                data: {
                    chunks,
                    fileHash,
                    fileName: file.name,
                    fileType
                }
            });
        }
    }, [createFileChunks, calculateHash]);

    // 取消上传
    const handleCancel = useCallback((fileHash: string) => {
        if (abortControllers.current[fileHash]) {
            abortControllers.current[fileHash].abort();
            delete abortControllers.current[fileHash];
            message.info('上传已取消');
        }
        setUploadStates(prev => prev.filter(state => state.fileHash !== fileHash));
        isUploadingRef.current[fileHash] = false;
    }, []);

    // 处理暂停上传
    const handlePause = useCallback((fileHash: string) => {
        if (abortControllers.current[fileHash]) {
            abortControllers.current[fileHash].abort();
            pausedUploads.current.add(fileHash);
            setUploadStates(prev => prev.map(state =>
                state.fileHash === fileHash
                    ? { ...state, isPaused: true }
                    : state
            ));
            message.info('上传已暂停');
        }
    }, []);

    // 处理继续上传
    const handleResume = useCallback((fileHash: string) => {
        const state = uploadStates.find(s => s.fileHash === fileHash);
        if (state) {
            pausedUploads.current.delete(fileHash);
            setUploadStates(prev => prev.map(s =>
                s.fileHash === fileHash
                    ? { ...s, isPaused: false }
                    : s
            ));
            handleUploadChunks(state.chunks, fileHash, state.fileName, state.fileType);
            message.info('继续上传');
        }
    }, [uploadStates, handleUploadChunks]);
    useEffect(() => {
        localStorage.setItem('fileUrls', JSON.stringify([]));
    }, []);
    return (
        <div >
            <div className={styles.container}>
                <Upload
                    multiple
                    customRequest={() => { }}
                    beforeUpload={() => false}
                    onChange={handleFileChange}
                    showUploadList={false}
                    disabled={uploadStates.some(state => state.isUploading)}
                >
                    <div className={styles.uploadArea}>
                        <UploadOutlined className={styles.uploadIcon} />
                        <div className={styles.uploadTip}>点击或拖拽图片到此处上传</div>
                        <div className={styles.networkStatus}>
                            网络状态: <span style={{ color: network.online ? '#52c41a' : '#f5222d' }}>{network.online ? '在线' : '离线'}</span><br />
                            {navigator.connection && (
                                <span>
                                    网络类型: {navigator.connection.effectiveType} 延迟: {navigator.connection.rtt}ms
                                </span>
                            )}
                        </div>
                    </div>
                </Upload> </div>

            {uploadStates.map(state => (
                <div key={state.fileHash} style={{ marginBottom: 24 }}>
                    <div className={styles.fileInfo}>
                        <b>文件名：</b>{state.fileName}
                        <Tag color={getFileTypeColor(state.fileType)} style={{ marginLeft: 8 }}>
                            {state.fileType}
                        </Tag>
                        {state.chunks.length > 0 && (
                            <span className={styles.fileSize}>
                                大小：{((state.chunks.reduce((acc, c) => acc + c.size, 0) / 1024 / 1024).toFixed(2))} MB
                            </span>
                        )}
                    </div>
                    <Progress
                        percent={Math.round(state.totalProgress)}
                        status={state.totalProgress === 100 ? 'success' : 'active'}
                        strokeWidth={16}
                        showInfo
                        style={{ marginBottom: 12 }}
                    />
                    {state.totalProgress === 100 && (
                        <div className={styles.successTip}>上传成功！</div>
                    )}
                    {state.isUploading && (
                        <div className={styles.buttonGroup}>
                            {!state.isPaused ? (
                                <Button
                                    onClick={() => handlePause(state.fileHash)}
                                    type="primary"
                                    block
                                    className={styles.pauseBtn}
                                >
                                    暂停上传
                                </Button>
                            ) : (
                                <Button
                                    onClick={() => handleResume(state.fileHash)}
                                    type="primary"
                                    block
                                    className={styles.resumeBtn}
                                >
                                    继续上传
                                </Button>
                            )}
                            <Button
                                onClick={() => handleCancel(state.fileHash)}
                                icon={<CloseOutlined />}
                                danger
                                block
                                className={styles.cancelBtn}
                            >
                                取消上传
                            </Button>
                        </div>
                    )}
                </div>
            ))}
        </div>
    );
};

export default LargeFileUpload;